function C_createGUI
% Build the basic GUI of the Controller
% composed of 
% - General Information
% - Paradigm Information
% - Module Information
%
% For both paradigm and module, there will be a set of buttons
% to show parameters, GUI, and start the respective part.

global CG Verbose;

NumberOfModules = CG.Paradigm.getNumberOfModules;
Modules = CG.Paradigm.getModules;

TitleSize = 12; TitleColor = CG.Colors.GUI.TextColor; Offset = 0;
Width = CG.GUI.Main.Width;
PixPerLine = 36;
HeightGeneral = 9*PixPerLine;
HeightParadigm = 1.3*PixPerLine;
HeightModules = 1.6*NumberOfModules * PixPerLine;
Heights = [HeightGeneral,HeightParadigm,HeightModules];
Height = sum(Heights);
Border = 0.01; BorderPix = Border*Width; PBorder = 0.03; cSep = 0.03;
PanelBorder = 0.01;
ButtonBorder = 0.05;

NormPH = (1-length(Heights)*Border)*Heights/sum(Heights); 
NormPW = 1-2.5*Border;
SS = get(0,'ScreenSize');
switch architecture
  case 'PCWIN'; CG.GUI.Main.Position = [5,SS(4)-Height-30];
  case 'MAC';  CG.GUI.Main.Position = [60,SS(4)-Height-45];
end

FigureSize = [CG.GUI.Main.Position,Width,sum(Height)];
cFIG = CG.GUI.Main.FIG;
figure(cFIG); clf; set(cFIG,'Position',FigureSize,...
  'NumberTitle','off','Name','Controller','Color',CG.Colors.GUI.Background,...
  'Toolbar','none','Menubar','none','Resize','off','NextPlot','new',...
  'DeleteFcn',{@C_CBF_closeController});
CG.GUI.FIGs = [];

%% ADD ALL PANELS
Sections = {'General','Paradigm','Modules'};
PanelPositions = axesDivide(1,NormPH,[Border,Border,1-2*Border,1-2*Border],[],[3*Border]);
for iS = 1:length(Sections)
  CG.GUI.Main.Panels.(Sections{iS}) = ...
    LF_addPanel(cFIG,Sections{iS},...
    TitleSize,TitleColor,CG.Colors.GUI.Panel,PanelPositions{iS});
end

%% BUILD GENERAL GUI
cPanel = CG.GUI.Main.Panels.General;

Positions = axesDivide([1],[1.5,1.5,1.5,1.5,1.5,1,1.2,1.2,1.2],...
  [PanelBorder,PanelBorder,1-2*PanelBorder,1-2*PanelBorder],[0.15],[0.15]);

% ADD DROPDOWN FOR USER,ANIMAL,PARADIGM
Cases = {'Lab','Setup','User','Animal','Paradigm'};

for iC = 1:length(Cases)
  cPositions = axesDivide([1,2],1,Positions{iC},[0.15],[0.15]);
  Loc = ['CG.Parameters.General.',Cases{iC}]; TT = ['Choose ',Cases{iC}];
  LF_addText(cPanel,cPositions{1},Cases{iC},TT);
  eval(['Choices = C_get',Cases{iC},'s;']);
  switch Cases{iC}
    case 'Lab';
      cCallback = {@C_CBF_changeLab}; 
      if isfield(CG.Parameters.General,Cases{iC})
        cValue = find(strcmp(CG.Parameters.General.(Cases{iC}),Choices));
      else cValue = 1;
      end
    case 'Paradigm'; 
      cName = CG.Paradigm.Name; cValue = find(strcmp(cName,Choices));
      cCallback = {@C_CBF_changeParadigm};
    case 'Setup';
      cName = CG.Parameters.General.Setup; cValue = find(strcmp(cName,Choices));
      cCallback = {@C_CBF_changeSetup};
    case 'Animal';
      cCallback = {@C_CBF_changeAnimal,[]};
      cValue = length(Choices);
    otherwise cCallback = {@C_CBF_setValue,Loc};
      if isfield(CG.Parameters.General,Cases{iC})
        cValue = find(strcmp(CG.Parameters.General.(Cases{iC}),Choices));
      else
        cValue = 1;
      end
  end
  CG.GUI.Main.([Cases{iC},'Selection']) = ...
    LF_addDropdown(cPanel,cPositions{2},Choices,cValue,cCallback,[],TT);
  set(CG.GUI.Main.([Cases{iC},'Selection']),'UserData',Choices);
  if length(cCallback)>1 cCallback{1}(CG.GUI.Main.([Cases{iC},'Selection']),[],cCallback{2}); end
end

% ADD FIELD FOR CURRENT RECORDING
cPositions = axesDivide([1,2],1,Positions{6},[0.15],[]);
TT = 'Current Recording Number'; 
cCallback = {@C_CBF_changeRecording};
cRecording = C_getRecording(CG.Parameters.General.Animal);
LF_addText(cPanel,cPositions{1},'Recording',TT);
CG.GUI.Main.RecordingSelection = LF_addEdit(cPanel,...
  cPositions{2},num2str(cRecording),cCallback,TT);
cCallback{1}(CG.GUI.Main.RecordingSelection);

cPositions = axesDivide([1,1,1,3],1,Positions{7},[0.15],[0.15]);
% Add Trial Info
TT='Current Trial';
LF_addText(cPanel,cPositions{1},['Trial'],TT);
CG.GUI.Main.Trial = LF_addText(cPanel,cPositions{2},'-',TT); 

% Add Current State of the Paradigm (updated by Paradigm)
% Maybe use an Eventlistener for the State (see OO documentation)
TT='Current State of the Paradigm';
LF_addText(cPanel,cPositions{3},['State'],TT);
CG.GUI.Main.State = LF_addText(cPanel,cPositions{4},'-',TT); 

cPositions = axesDivide([1.5,2.5,0.6,1.5],1,Positions{8},[0.15],[0.15]);
% Add Free Memory Info (RAM & HD)
TT='Free Memory (RAM / HD)';
LF_addText(cPanel,cPositions{1},['Memory'],TT);
CG.GUI.Main.Space = LF_addText(cPanel,cPositions{2},'0 / 0',TT); 
C_setDiskspace;

% Verbose checkbox
Loc = ['Verbose'];
CG.GUI.Main.Verbose.State = LF_addCheckbox(cPanel,cPositions{3},Verbose,...
  {@C_CBF_setValue,Loc});
LF_addText(cPanel,cPositions{4},'Verbose'); 

% DATABASE & BACKUP 

% Backup Button (inactive during recording)
Loc = 'Backup'; TT = 'Backup Data to Server';
CG.GUI.Main.BackupButton = ...
    LF_addButton(cPanel,Positions{9},'Backup','Push','C_backupToServer',TT);

%% BUILD PARADIGM GUI

% ADD BUTTONS
Buttons = {'Modify','Show','Start'};
Types = {'Push','Toggle','Toggle'};
ButtonTips = {'Modify the parameters of the paradigm','Show the graphics of the paradigm','Start/Stop the paradigm'};
ButtonPositions = axesDivide(length(Buttons),1,...
  [ButtonBorder,ButtonBorder,1-2*ButtonBorder,1-2*ButtonBorder],[0.1],[]);
for iB = 1:length(Buttons)
  cCallback = {eval(['@C_CBF_',lower(Buttons{iB}),'Paradigm']),CG.Paradigm.Name};
  CG.GUI.Main.Paradigm.([Buttons{iB},'Button']) = ...
    LF_addButton(CG.GUI.Main.Panels.Paradigm,ButtonPositions{iB},Buttons{iB},Types{iB},...
    cCallback,ButtonTips{iB});
  CG.GUI.Parameters.Paradigm.FIG = 100000;
end

%% BUILD MODULES GUI
ModulePositions = axesDivide(1,NumberOfModules,...
  [PanelBorder,PanelBorder,1-2*PanelBorder,1-2*PanelBorder],[],[0.15]);
Buttons = {'Modify','Show','Start'};
Types = {'Push','Toggle','Toggle'};
ButtonTips = {'Modify the parameters of this module','Show the graphics of this module','Start/Stop this module'};
ButtonPositions = axesDivide(length(Buttons),1,...
  [ButtonBorder,ButtonBorder,1-2*ButtonBorder,1-2*ButtonBorder],[0.1],[]);
for iM = 1:NumberOfModules
  cType = Modules(iM).Type;
  cName = Modules(iM).Name;
  cIDType = Modules(iM).IDType;
  
  % ADD PANEL FOR EACH MODULE
  cPanel = LF_addPanel(CG.GUI.Main.Panels.Modules,[cName,' (',cType,')'],...
    TitleSize,TitleColor,CG.Colors.GUI.PanelModule,ModulePositions{iM});
  CG.GUI.Main.Modules.(cType)(cIDType).Panel = cPanel;
  % ADD BUTTONS FOR EACH MODULE
  for iB = 1:length(Buttons)
    cCallback = {eval(['@C_CBF_',lower(Buttons{iB}),'Module']),cType,cIDType,cName};
    CG.GUI.Main.Modules.(cType)(cIDType).([Buttons{iB},'Button']) = ...
      LF_addButton(cPanel,ButtonPositions{iB},Buttons{iB},Types{iB},...
      cCallback,ButtonTips{iB});
  end
  
  % ASSIGN THE FIGURE NUMBERS FOR EACH PARAMETER GUI
  CG.GUI.Parameters.Modules.(cType)(cIDType).FIG = 100000+iM;
end

%% HELPER FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function h = LF_addPanel(Parent,Title,TitleSize,TitleColor,Color,Position,TitlePos)
% DRAW A SIMPLE PANEL
global CG
if ~exist('TitlePosition','var') TitlePos = 'centertop'; end
h = uipanel('Parent',Parent,'Title',Title,...
  'FontSize',TitleSize,'FontName',CG.GUI.Props.Font,'HighlightColor',CG.Colors.GUI.PanelHighlight,...
  'ForeGroundColor',TitleColor,'TitlePosition',TitlePos,'BackGroundColor',Color,...
  'Units','normalized','Position',Position,'BorderType','line','FontSize',CG.GUI.Props.FontSizePanel);

function h = LF_addDropdown(Panel,Pos,Strings,Val,CBF,UD,Tooltip,Tag,Color,FontSize);
global CG
if ~exist('Color','var') | isempty(Color) Color = [1,1,1]; end
if ~exist('Tag','var') | isempty(Tag) Tag = ''; end
if ~exist('CBF','var') | isempty(CBF) CBF=''; end
if ~exist('Tooltip','var') | isempty(Tooltip) Tooltip = ''; end

h=uicontrol('Parent',Panel,'Style','popupmenu',...
  'String',Strings,'Val',Val,'FontName',CG.GUI.Props.Font,...
  'Callback',CBF,'Units','normalized',...
  'Tag',Tag,'Position',Pos,'BackGroundColor',Color,'TooltipString',Tooltip,'FontSize',CG.GUI.Props.FontSizePanel);
set(h,'UserData',UD)

function h = LF_addButton(Panel,Pos,String,Type,CBF,Tooltip,Tag,FGColor,BGColor);
global CG
if ~exist('BGColor','var') | isempty(FGColor) FGColor = [0,0,0]; end
if ~exist('BGColor','var') | isempty(BGColor) BGColor = [1,1,1]; end
if ~exist('Tag','var') | isempty(Tag) Tag = ''; end
if ~exist('CBF','var') | isempty(CBF) CBF=''; end
if ~exist('Tooltip','var') | isempty(Tooltip) Tooltip = ''; end
switch lower(Type)
  case 'toggle';
    h=uicontrol('Parent',Panel,'Style','togglebutton',...
      'String',String,'FontName',CG.GUI.Props.Font,...
      'Value',0,'Callback',CBF,...
      'Units','normalized','Position',Pos,'Tag',Tag,...
      'ToolTipString',Tooltip,'ForegroundColor',FGColor,'BackGroundColor',BGColor,...
      'FontSize',CG.GUI.Props.FontSizePanel);
  case 'push';
    h=uicontrol('Parent',Panel,'Style','pushbutton',...
      'String',String,'FontName',CG.GUI.Props.Font,...
      'Callback',CBF,'Units','normalized','Position',Pos,'Tag',Tag,...
      'ToolTipString',Tooltip,'ForegroundColor',FGColor,'BackGroundColor',BGColor,...
      'FontSize',CG.GUI.Props.FontSizePanel);
end

function h = LF_addCheckbox(Panel,Pos,Val,CBF,Tooltip,Tag,Color);
global CG
if ~exist('Color','var') | isempty(Color) Color = CG.Colors.GUI.Panel; end
if ~exist('Tag','var') | isempty(Tag) Tag = ''; end
if ~exist('CBF','var') | isempty(CBF) CBF=''; end
if ~exist ('Tooltip','var') | isempty(Tooltip) Tooltip = ''; end
h=uicontrol('Parent',Panel,'Style','checkbox',...
  'Value',Val,'Callback',CBF,'Units','normalized',...
  'Tag',Tag,'Position',Pos,'BackGroundColor',Color,'Tooltip',Tooltip);

 function h = LF_addEdit(Panel,Pos,String,CBF,Tooltip,Tag,Color);
global CG
if ~exist('Color','var') | isempty(Color) Color = [1,1,1]; end
if ~exist('Tag','var') | isempty(Tag) Tag = ''; end
if ~exist('CBF','var') | isempty(CBF) CBF=''; end
if ~exist('Tooltip','var') | isempty(Tooltip) Tooltip = ''; end
if ~isstr(String) String = n2s(String); end
h=uicontrol('Parent',Panel,'Style','edit',...
  'String',String,'FontName',CG.GUI.Props.Font,...
  'Callback',CBF,'Units','normalized',...
  'Tag',Tag,'Position',Pos,'BackGroundColor',Color,'ToolTipString',Tooltip,'FontSize',CG.GUI.Props.FontSizePanel);

function h = LF_addText(Panel,Pos,String,Tooltip,Tag,FGColor,BGColor,varargin);
global CG
if ~exist('BGColor','var') | isempty(BGColor) BGColor = CG.Colors.GUI.Panel; end
if ~exist('FGColor','var') | isempty(FGColor) FGColor = CG.Colors.GUI.TextColor; end
if ~exist('Tag','var') | isempty(Tag) Tag = ''; end
if ~exist('CBF','var') | isempty(CBF) CBF=''; end
if ~exist('Tooltip','var') | isempty(Tooltip) Tooltip = ''; end
h=uicontrol('Parent',Panel,'Style','text',...
  'String',String,'FontName',CG.GUI.Props.Font,...
  'Units','normalized','Position',Pos-[0,0.01,0,0],...
  'Tag',Tag,'ToolTipString',Tooltip,'HorizontalAlignment','left',...
  'ForegroundColor',FGColor,'BackGroundColor',BGColor,'FontSize',CG.GUI.Props.FontSizePanel,varargin{:});

function C_CBF_setValue(O,event,location,index)
% General function to set properties from the GUI

global CG Verbose

switch lower(get(O,'Style'))
  case {'edit'}; 
    Entry = get(O,'String'); Num = str2num(Entry);
    if ~isempty(Num) Entry = str2num(Entry); end;
  case {'popupmenu'}; % String is not used, since sometimes not representable
    Value = get(O,'Value'); Entries = get(O,'String'); 
    Entry = Entries{Value};
  case {'checkbox'};
    Entry = get(O,'Value');
end
eval([location,' = Entry;']);

% CHANGE THE LAB, WHICH REQUIRES CHANGING THE 
function C_CBF_changeLab(O,event)
global CG;
Labs = get(O,'String');
Lab = Labs{get(O,'Value')};
CG.Parameters.General.Lab = Lab;
set(CG.GUI.Main.SetupSelection,'String',C_getSetups(Lab),'Value',1);

% CHANGE THE LAB, WHICH REQUIRES CHANGING THE 
function C_CBF_changeSetup(O,event)
global CG;
Setups = get(O,'String');
Setup = Setups{get(O,'Value')};
CG.Parameters.General.Setup = Setup;
eval(['C_Setup_',Setup]);

% RESTART CONTROLLER WHEN THE PARADIGM IS CHANGED
function C_CBF_changeParadigm(O,event)
  global CG;
  Paradigms = get(O,'String');
  Paradigm = Paradigms{get(O,'Value')};
  Controller('Paradigm',Paradigm,'Parameters.General.Lab',CG.Parameters.General.Lab,...
    'Parameters.General.Setup',CG.Parameters.General.Setup,...
    'Parameters.General.User',CG.Parameters.General.User,...
    'Parameters.General.Animal',CG.Parameters.General.Animal);

% RESTART CONTROLLER WHEN THE PARADIGM IS CHANGED
function C_CBF_changeAnimal(O,event,Loc)
global CG;
Animals = get(O,'String');
Animal = Animals{get(O,'Value')};
CG.Parameters.General.Animal = Animal;
CG.Files.AnimalPath = [CG.Files.DataPath,CG.Parameters.General.Animal,filesep];  
CG.Files.AnimalPathTmp =  [CG.Files.DataPathTmp,CG.Parameters.General.Animal,filesep]; 
cRecording = C_getRecording(Animal); 
try
  set(CG.GUI.Main.RecordingSelection,'String',num2str(cRecording));
  CG.Parameters.General.Recording = cRecording;
  C_generateIdentifier;
end

function C_CBF_changeRecording(O,event,Loc)
global CG;
cRecording = str2num(get(O,'String'));
CG.Parameters.General.Recording = cRecording;
C_generateIdentifier;
CG.Files.RecordingPath = [CG.Files.AnimalPath,'R',num2str(CG.Parameters.General.Recording),filesep];
CG.Files.RecordingPathTmp = [CG.Files.AnimalPathTmp,'R',num2str(CG.Parameters.General.Recording),filesep];

% OPEN PARAMETER GUI FOR THE PARADIGM / EACH MODULE
function C_CBF_modifyParadigm(O,event,Name)
C_openParameterGUI('Name',Name,'MainType','Paradigm');

% SHOW PARADIGM GUI
function C_CBF_showParadigm(O,event,Name)
global CG;
CG.Paradigm.showDisplay(get(O,'Value'));

% START MODULE
function C_CBF_startParadigm(O,event,Name)
global CG;
switch get(O,'Value')
  case 1;  
    Choice = questdlg(['Do you want to continue with Animal "',CG.Parameters.General.Animal,'"??'],...
      'Animal Dialog','Yes','No','No');
    switch Choice
      case 'No';   set(O,'Value',0);  return;
      otherwise
    end
    set(O,'BackgroundColor',[1,0,0]); start(CG.Paradigm);
   
  case 0;  set(O,'BackgroundColor',[1,1,1]); stop(CG.Paradigm); 
end

% OPEN PARAMETER GUI FOR THE PARADIGM / EACH MODULE
function C_CBF_modifyModule(O,event,Type,ID,Name)
C_openParameterGUI('Type',Type,'Name',Name,'ID',ID,'MainType','Module');

% SHOW MODULE GUI
function C_CBF_showModule(O,event,Type,ID,Name)
State =  get(O,'Value');
if State Color = [0.7,0.7,0.7]; else Color = [1,1,1]; end 
set(O,'BackGroundColor',Color);
eval(['C_show',Type,'(ID,State)']);

% START MODULE
function C_CBF_startModule(O,event,Type,ID,Name)
switch get(O,'Value')
  case 1; eval(['C_start',Type,'(ID)']);
  case 0; eval(['C_stop',Type,'(ID,0)']);
end
  
function C_CBF_closeController(O,event)
global CG 

% TRY TO STOP ALL MODULES
if CG.Paradigm.ParadigmActive CG.Paradigm.stop; end

% TRY TO CLOSE ALL FIGURES
for iF=CG.GUI.AllFigures; try; close(iF); end; end
switch architecture
  case 'PCWIN';
    if isfield(CG.Sessions,'Video')
      for iV=1:length(CG.Sessions.Video)
        delete(CG.Sessions.Video(iV).S);
      end
    end
end
if isfield(CG.Sessions,'Arduino')
  for iV=1:length(CG.Sessions.Arduino)
   delete(CG.Sessions.Arduino(iV).S);
  end
end
